/**
  ******************************************************************************
  * @file           : updata.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * 固件放在外挂SPI FLASH中，FLASH开始地址的前1M空间用于存放固件。固件的最后16
  * 字节位MD5检验值
  *
  ******************************************************************************
  */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stdio.h"
#include "flash_if.h"
#include "updata.h"
#include "iic_eeprom.h"
#include "md5.h"
#include "spi_flash.h"
#include "common.h"
#include "flash.h"
/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
Fw_TypeDef Fw;
static uint8_t RxBuf[FLASH_PAGE_SIZE];
/* Private function prototypes -----------------------------------------------*/

/* Private functions ---------------------------------------------------------*/
/**
 * @brief  
 * @param  None
 * @retval None
 */
int8_t FirmwareIsOk(void)
{
	uint32_t readAddr;
	uint32_t  readLength;
	MD5_CTX md5;
	uint8_t md5Buf[16] = {0};
    uint8_t md5TempBuf[16] = {0};

	/* read firmware from flash, calculate md5 */
	MD5_Init(&md5);
    
	for(readAddr = Fw.Addr; readAddr < Fw.Size + Fw.Addr;)
	{
		if(readAddr + FLASH_PAGE_SIZE + 16 < Fw.Size + Fw.Addr)
		{
            readLength = FLASH_PAGE_SIZE;
			SPI_FLASH_ReadData(readAddr, RxBuf, readLength);
            printf(">> readAddr = 0x%08X, length = %d.\r\n", readAddr, readLength);
			/* updata md5 */
			MD5_Update(&md5, RxBuf, readLength);
		}
		else
		{
			readLength = Fw.Size + Fw.Addr - readAddr;
            if(readLength <= FLASH_PAGE_SIZE)
            {
                SPI_FLASH_ReadData(readAddr, RxBuf, readLength);
                printf(">> readAddr = 0x%08X, length = %d.\r\n", readAddr, readLength);
                MD5_Update(&md5, RxBuf, readLength - 16);
                /* 复制MD5 */
                memcpy(md5TempBuf, &RxBuf[readLength - 16], 16);
                break;
            }
            else
            {
                SPI_FLASH_ReadData(readAddr, RxBuf, readLength - 16);
                printf(">> readAddr = 0x%08X, length = %d.\r\n", readAddr, readLength);
                MD5_Update(&md5, RxBuf, readLength - 16);
                readAddr += readLength - 16;
                SPI_FLASH_ReadData(readAddr, md5TempBuf, 16);
                printf(">> readAddr = 0x%08X, length = 16.\r\n", readAddr);
                break;
            }
		}
        readAddr += readLength;
	}
    
    MD5_Final(&md5, md5Buf);
    /* 比较MD5是否相等 */
    if(Buffercmp(md5Buf, md5TempBuf, 16) == 0)
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

/**
 * @brief
 * @param  None
 * @retval None
 */

int8_t CopyFirmwareToFlash(void)
{
	uint32_t readAddr;
	uint32_t writeAddr = APPLICATION_ADDRESS;
	uint32_t  length;

	for(readAddr = Fw.Addr; readAddr < Fw.Size;)
	{
		if(readAddr + sizeof(RxBuf) < Fw.Size + Fw.Addr)
		{
			length = sizeof(RxBuf);
			/* read firmware from spi flash */
			SPI_FLASH_ReadData(readAddr, RxBuf, length);
			/*  */
            FLASH_Erase(writeAddr, 1);
			if(FLASH_If_Write(writeAddr, (uint32_t*)RxBuf, (length>>2)) == FLASHIF_OK)
			{
                printf("readAddr=%08x, writeAddr=%08x, length=%u Byte\r\n", readAddr, writeAddr, length);
				/*ַ */
				readAddr += length;
				/*ַ */
				writeAddr += length;
			}
			else
			{
				break;
			}
		}
		else
		{
			length = Fw.Size + Fw.Addr - readAddr;
			if(length % 4 != 0)
			{
				length += 4 - (length % 4);
			}
			/*  */
			SPI_FLASH_ReadData(readAddr, RxBuf, length);
			/*  */
            FLASH_Erase(writeAddr, 1);
			if(FLASH_If_Write(writeAddr, (uint32_t*)RxBuf, (length>>2)) == FLASHIF_OK)
			{
				printf("readAddr=%08x, writeAddr=%08x, length=%u Byte\r\n",readAddr, writeAddr, length);
				return 0;
			}
			else
			{
				break;
			}
		}
	}

	return -1;
}
/************************ (C) COPYRIGHT 2016-2022,xEndLess *****END OF FILE****/
